classdef Material < handle & matlab.mixin.Heterogeneous
    % MATERIAL 材料模型基类 
    % 该类根据材料ID和可变数量的参数来创建对象，未提供的参数将使用默认值。
    
    properties (SetAccess = immutable)
        % 一旦创建，所有属性都不可变，确保数据一致性
        MaterialID      % 材料类型
        MaterialName    
        YoungsModulus   
        PoissonsRatio   
        Area            
        Thickness       
        Density         
    end
    
    methods
        function obj = Material(id, varargin)
            % 构造函数 - 根据ID和可变参数创建材料对象
            % 输入:
            %   id        - 整型，材料ID，决定参数解析方式
            %   varargin  - 可变参数，其含义取决于id
            
            % --- 1. 验证ID ---
            if ~isnumeric(id) || id <= 0 || mod(id,1) ~= 0
                error('Material:InvalidID', 'MaterialID 必须是正整数。');
            end
            
            obj.MaterialID = id;

            % --- 2. 根据ID直接分配参数 ---
            num_provided = numel(varargin);
    
            
            % 根据ID设置特定的默认名称和参数验证
            switch id
                case 1  % 桁架材料：参数为 E, A
                    if num_provided > 2 || num_provided == 1
                        error('Material:TooManyInputs', ...
                              '对于ID %d（桁架材料），最多期望 2 个参数 (E, A)，但提供了 %d 个。', ...
                              id, num_provided);
                    end
               
                    obj.MaterialName = 'Truss_Material';
                    obj.YoungsModulus = varargin{1};
                    obj.Area = varargin{2};
                    
                case 2  % 平面应力板：参数为 E, nu, t
                    if num_provided == 3
                        % 分配参数
                        obj.YoungsModulus = varargin{1};
                        obj.PoissonsRatio = varargin{2};
                        obj.Thickness = varargin{3};
                    elseif num_provided > 3 || num_provided == 1
                        error('Material:TooManyInputs', ...
                              '对于ID %d（平面应力板），最多期望 3 个参数 (E, nu, t)，但提供了 %d 个。',id, num_provided);
                    else 
                        warning("对于ID %d（平面应力板），将使用默认厚度计算!",id);
                        obj.Thickness = 1;
                    end
                otherwise
                    error('Material:UnsupportedID', '不支持的材料ID: %d。', id);
            end
            
        end
        
        % 本构矩阵计算方法
        function D = getTrussStressMatrix(obj)
            if obj.Area == 0
                warning('Material:InvalidPropertyForProblemType', ...
                        '材料ID %d (Name: %s) 的横截面积 为0，桁架刚度将为0。', ...
                        obj.MaterialID, obj.MaterialName);
            end
            D = obj.YoungsModulus * obj.Area;
        end

        function D = getPlaneStressMatrix(obj)
            E = obj.YoungsModulus; nu = obj.PoissonsRatio;
            factor = E / (1 - nu^2);
            D = factor * [1, nu, 0; nu, 1, 0; 0, 0, (1-nu)/2];
        end

        function D = getPlaneStrainMatrix(obj)
            E = obj.YoungsModulus; nu = obj.PoissonsRatio;
            factor = E / ((1+nu) * (1-2*nu));
            D = factor * [1-nu, nu, 0; nu, 1-nu, 0; 0, 0, (1-2*nu)/2];
        end

        function D = getConstitutiveMatrix(obj)
            switch obj.MaterialID
                case 1
                    D = obj.getTrussStressMatrix();
                case 2
                    D = obj.getPlaneStressMatrix();
                case 3
                    D = obj.getPlaneStrainMatrix();
                otherwise
                    error('Material:UnsupportedID', '不支持的材料ID: %d。', obj.MaterialID);
            end
        end

        function stress = computeStress(obj, strain)
            D = obj.getConstitutiveMatrix();
            stress = D * strain;
        end
    end
end